
import threading

class ThreadTask():
    def __init__(self,thread_func,priority=0,finish_func=None,error_func=None):
        self._thread_func=thread_func
        self._finish_func=finish_func
        self._error_func=error_func
        self.priority=priority
        
    def run(self):
        try:
            self._thread_func()
        except:
            if self._error_func:
                self._error_func()
            else:
                import traceback
                traceback.print_exc()
        else:
            if self._finish_func:
                self._finish_func()
            

class ThreadPool(object):
    _instance=None
    
    def __new__(cls):
        if not ThreadPool._instance:
            ThreadPool._instance=object.__new__(ThreadPool)
            ThreadPool._instance._real_init()
        return ThreadPool._instance
    
    def __init__(self):
        pass
    
    def _real_init(self):
        super(ThreadPool,self).__init__()
        
        #######################
        self._max_thread=5
        #######################
        self._thread_pool={}
        self._task_queue=[]
        self._mutex=threading.Lock()
        self._semaphore_queue=threading.Semaphore(0)
        self._semaphore_free=threading.Semaphore(self._max_thread)
        self._stop=False
        
        self._daemon_thread=threading.Thread(target=self._run)
        self._daemon_thread.start()
        
    def stop(self):
        self._stop=True
        
    def addTask(self,thread_func,priority=0,finish_func=None,error_func=None):
        task=ThreadTask(thread_func,priority,finish_func,error_func)
        self._mutex.acquire()
        self._task_queue.append(task)
        self._task_queue.sort(key=lambda x:x.priority)
        self._mutex.release()
        self._semaphore_queue.release()
    
    def _run(self):
        while(not self._stop):
            self._semaphore_queue.acquire()
            
            self._mutex.acquire()
            task=self._task_queue.pop()
            self._mutex.release()
            
            self._semaphore_free.acquire()
            
            new_thread=threading.Thread(target=self._fac_run_task(task))
            self._thread_pool[task]=new_thread
            new_thread.start()
            
        
    def _fac_run_task(self,task):
        def _run_task():
            task.run()
            
            self._mutex.acquire()
            self._thread_pool.pop(task)
            self._mutex.release()
            
            self._semaphore_free.release()
        return _run_task
        